home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / sysdeps / posix / pipestream.c < prev    next >
C/C++ Source or Header  |  1993-12-16  |  6KB  |  224 lines

  1. /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <errno.h>
  21. #include <stddef.h>
  22. #include <signal.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <sys/types.h>
  26. #include <sys/wait.h>
  27. #include <unistd.h>
  28. #include <fcntl.h>
  29.  
  30. #define    SH_PATH    "/bin/sh"    /* Shell to run.  */
  31. #define    SH_NAME    "sh"        /* Name to give it.  */
  32.  
  33. /* Structure describing a popen child.  */
  34. struct child
  35.   {
  36.     pid_t pid;            /* PID of the child.  */
  37.     __ptr_t cookie;        /* Original cookie from fdopen.  */
  38.     __io_functions funcs;    /* Original functions from fdopen.  */
  39.   };
  40.  
  41. /* io_functions for pipe streams.
  42.    These all simply call the corresponding
  43.    original function with the original cookie.  */
  44.  
  45. #define FUNC(type, name, args)                              \
  46.   static type DEFUN(__CONCAT(child_,name), args, __CONCAT(name,decl))          \
  47.   {                                          \
  48.     struct child *c = (struct child *) cookie;                      \
  49.     {                                          \
  50.       __ptr_t cookie = c->cookie;                          \
  51.       return (*c->funcs.__CONCAT(__,name)) args;                  \
  52.     }                                          \
  53.   }
  54.  
  55. #define readdecl PTR cookie AND register char *buf AND register size_t n
  56. FUNC (int, read, (cookie, buf, n))
  57. #define writedecl PTR cookie AND register CONST char *buf AND register size_t n
  58. FUNC (int, write, (cookie, buf, n))
  59. #define seekdecl PTR cookie AND fpos_t *pos AND int whence
  60. FUNC (int, seek, (cookie, pos, whence))
  61. #define closedecl PTR cookie
  62. FUNC (int, close, (cookie))
  63. #define filenodecl PTR cookie
  64. FUNC (int, fileno, (cookie))
  65.  
  66. static const __io_functions child_funcs
  67.   = { child_read, child_write, child_seek, child_close, child_fileno };
  68.  
  69. /* Open a new stream that is a one-way pipe to a
  70.    child process running the given shell command.  */
  71. FILE *
  72. DEFUN(popen, (command, mode), CONST char *command AND CONST char *mode)
  73. {
  74.   pid_t pid;
  75.   int pipedes[2];
  76.   FILE *stream;
  77.   struct child *child;
  78.  
  79.   if (command == NULL || mode == NULL || (*mode != 'r' && *mode != 'w'))
  80.     {
  81.       errno = EINVAL;
  82.       return NULL;
  83.     }
  84.  
  85.   /* Create the pipe.  */
  86.   if (pipe(pipedes) < 0)
  87.     return NULL;
  88.  
  89.   /* Fork off the child.  */
  90.   pid = __vfork ();
  91.   if (pid == (pid_t) -1)
  92.     {
  93.       /* The fork failed.  */
  94.       (void) close (pipedes[0]);
  95.       (void) close (pipedes[1]);
  96.       return NULL;
  97.     }
  98.   else if (pid == (pid_t) 0)
  99.     {
  100.       /* We are the child side.  Make the write side of
  101.      the pipe be stdin or the read side be stdout.  */
  102.  
  103.       CONST char *new_argv[4];
  104.  
  105.       if ((*mode == 'w' ? dup2(pipedes[STDIN_FILENO], STDIN_FILENO) :
  106.       dup2(pipedes[STDOUT_FILENO], STDOUT_FILENO)) < 0)
  107.     _exit(127);
  108.  
  109.       /* Close the pipe descriptors.  */
  110.       (void) close(pipedes[STDIN_FILENO]);
  111.       (void) close(pipedes[STDOUT_FILENO]);
  112.  
  113.       /* Exec the shell.  */
  114.       new_argv[0] = SH_NAME;
  115.       new_argv[1] = "-c";
  116.       new_argv[2] = command;
  117.       new_argv[3] = NULL;
  118.       (void) execve(SH_PATH, (char *CONST *) new_argv, environ);
  119.       /* Die if it failed.  */
  120.       _exit(127);
  121.     }
  122.  
  123.   /* We are the parent side.  */
  124.  
  125.   /* Close the irrelevant side of the pipe and open the relevant side as a
  126.      new stream.  Mark our side of the pipe to close on exec, so new children
  127.      won't see it.  */
  128.   if (*mode == 'r')
  129.     {
  130.       (void) close (pipedes[STDOUT_FILENO]);
  131.       (void) fcntl (pipedes[STDIN_FILENO], F_SETFD, FD_CLOEXEC);
  132.       stream = fdopen (pipedes[STDIN_FILENO], mode);
  133.     }
  134.   else
  135.     {
  136.       (void) close (pipedes[STDIN_FILENO]);
  137.       (void) fcntl (pipedes[STDOUT_FILENO], F_SETFD, FD_CLOEXEC);
  138.       stream = fdopen (pipedes[STDOUT_FILENO], mode);
  139.     }
  140.  
  141.   if (stream == NULL)
  142.     goto error;
  143.  
  144.   child = (struct child *) malloc (sizeof (struct child));
  145.   if (child == NULL)
  146.     goto error;
  147.  
  148.   {
  149.     /* Make sure STREAM has its functions set before
  150.        we try to squirrel them away in CHILD.  */
  151.     extern void __stdio_check_funcs __P ((FILE *));
  152.     __stdio_check_funcs (stream);
  153.   }
  154.  
  155.   child->pid = pid;
  156.   child->cookie = stream->__cookie;
  157.   child->funcs = stream->__io_funcs;
  158.   stream->__cookie = (PTR) child;
  159.   stream->__io_funcs = child_funcs;
  160.   stream->__ispipe = 1;
  161.   return stream;
  162.  
  163.  error:
  164.   {
  165.     /* The stream couldn't be opened or the child structure couldn't be
  166.        allocated.  Kill the child and close the other side of the pipe.  */
  167.     int save = errno;
  168.     (void) kill (pid, SIGKILL);
  169.     if (stream == NULL)
  170.       (void) close (pipedes[*mode == 'r' ? STDOUT_FILENO : STDIN_FILENO]);
  171.     else
  172.       (void) fclose (stream);
  173. #ifndef    NO_WAITPID
  174.     (void) waitpid (pid, (int *) NULL, 0);
  175. #else
  176.     {
  177.       pid_t dead;
  178.       do
  179.     dead = wait ((int *) NULL);
  180.       while (dead > 0 && dead != pid);
  181.     }
  182. #endif
  183.     errno = save;
  184.     return NULL;
  185.   }
  186. }
  187.  
  188. /* Close a stream opened by popen and return its status.
  189.    Returns -1 if the stream was not opened by popen.  */
  190. int
  191. DEFUN(pclose, (stream), register FILE *stream)
  192. {
  193.   struct child *c;
  194.   pid_t pid, dead;
  195.   int status;
  196.  
  197.   if (!__validfp(stream) || !stream->__ispipe)
  198.     {
  199.       errno = EINVAL;
  200.       return -1;
  201.     }
  202.  
  203.   c = (struct child *) stream->__cookie;
  204.   pid = c->pid;
  205.   stream->__cookie = c->cookie;
  206.   stream->__io_funcs = c->funcs;
  207.   free ((PTR) c);
  208.   stream->__ispipe = 0;
  209.   if (fclose (stream))
  210.     return -1;
  211.  
  212. #ifndef    NO_WAITPID
  213.   dead = waitpid (pid, &status, 0);
  214. #else
  215.   do
  216.     dead = wait (&status);
  217.   while (dead > 0 && dead != pid);
  218. #endif
  219.   if (dead != pid)
  220.     status = -1;
  221.  
  222.   return status;
  223. }
  224.